#include "user.h"
#include "fcntl.h"
#include "console.h"
#include "types.h"

#define BUF_SIZE 256
#define MAX_LINE_NUMBER 256
//#define MAX_LINE_LENGTH 256

#define MAX_LINE_INIT_LIMIT 77
#define MAX_LINE_SHOW_LIMIT 73
#define MAX_ROW_LIMIT 12

#define O_RDONLY  0x000
#define O_WRONLY  0x001
#define O_RDWR    0x002
#define O_CREATE  0x200
#define DEBUG 0

#define ARG_LEGAL      0x1000
#define ARG_DEFICIENCY 0x1001

#define FILE_LEGAL     0x2000
#define FILE_OPEN_FAIL 0x2001
#define FILE_CREATE_FAIL 0x2002

#define SET_ROW 0x101
#define SET_COL 0x102

#define ADD 0x4001
#define SUB 0X4002

#define EQUAL_EVER 0x5000

#define ROW_LESS 0x5001
#define ROW_MORE 0x5002
#define COL_LESS 0x5003
#define COL_MORE 0x5004
#define COL_LESS_ROW_LESS 0x5005
#define COL_MORE_ROW_LESS 0x5006
#define COL_LESS_ROW_MORE 0x5007
#define COL_MORE_ROW_MORE 0x5008

#define KEY_UP -30
#define KEY_DOWN -29
#define KEY_LEFT -28
#define KEY_RIGHT -27
#define KEY_ESC 27
#define KEY_END -31
#define KEY_HOME -32
#define KEY_BACK_SPACE 8
#define KEY_ENTER 0
#define KEY_DELETE -23
#define KEY_INSERT -24
#define KEY_COLON 58
#define KEY_LINE_FEED 13

#define KEY_LOWER_i 105
#define KEY_LOWER_n 110
#define KEY_UPPER_N 78

#define KEY_DIV 47
#define KEY_PAGE_UP -26
#define KEY_PAGE_DOWN -25
#define KEY_SPACE 32
#define KEY_QUESTION_MARK 63

#define KEY_CTRL_A 1
#define KEY_CTRL_E 5

#define COMMAND_QUIT "q"
#define COMMAND_QUIT_FORCE "q!"
#define COMMAND_WRITE  "w"
#define COMMAND_WRITE_QUIT "wq"

#define FLAG_STATE_HAS_WRITE 0x1 << 0

#define NULL 0

#define FLAG_KEY_HAS_PRESS_ESC 0x1 << 0
#define FLAG_KEY_HAS_PRESS_COLON 0x1 << 1

#define FLAG_CLEAR     0x0

//#define LESS_EQUAL_ZERO 0x5003
//#define MORE_EQUAL_LIMIT 0x5004

#define SUCESS 0
#define FAIL   1

#define VIEW_CURSOR 24

#define EVENT_INSERT 0x101
#define EVENT_DELETE 0x102

#define MODE_COMMAND    0x200
#define MODE_COMMAND_TEXT 0x201
#define MODE_INSERT 0x210
#define MODE_SUSPEND 0x220

#define EVENT_DELETE_STAY 0x1021
#define EVENT_DELETE_MOVE 0x1022

void prints(char *text);
void log(char *text);
void logi(char *statement, int intValue);

void show_text_same(char *text, int line_number);
int show_text(char *text[], int *line_number, int max_len, int mode);
char **readFile(int fd, int buf_size, int text_num, int text_length, int max_len, int *line_number);
char *strcat_n(char *des, char *src, int len, int max_len);
char *strcat2(char *des, char *src, int max_len);
char *blank_same_cpy(int before, int row, int col, int max_length);
void drawCursor(int *line_number, int row, int col, char **pString);
int wait_for_input(char *text[], int row, int col, int *line_number, int mode, int max_len);
void only_show_text(char *text[], int row, int col, int *line_number);

int judgeArg(int type);
int isArgLegal(int argc, char *argv[]);
int isFileLegal(int fd, int type);
int judgeFile(int type);
char *malloc1DimensionalChar(int size);
char **malloc2DimensionalChar(int size1, int size2);

int cursorNext(int rowOrCol, int *line_number, char **text, int i, int type, int event);
int moveCursor(int rowOrCol, int type, int *line_number, char **text, int addOrSub, int event);
int cursorColToRow(int type, int col_type, int *pInt, char **pString, int i, int event);
int setPage(int max_row);

int getCurrentMaxLengthLabel(char **text);
int getCurrentMaxLength(char **text);
void initGlobal();
char *itoa2(int a);
void addLogPrintStr(char *str);
int getMaxLength(char **text, int row);
int draw(char *text[], int *line_number, int max_len);
int getMaxLengthLabel(char **text, int row);
void insertCharInside(char **text, int ch, int *line_number, int row, int col);
void insertChar(char **text, int ch, int *line_number, int row, int col);
void clearScreen();
void createNewTextLine(char **text, int *line_number);
int deleteCharInside(char **text, int row, int col, int *line_number);
void deleteChar(char **text, int *line_number, int row, int col);
char *trim(char *text);
void clearCommandKeyFlag();
int hasStateWrite();
int resolveSuspendMode(int ch);
int hasPressEsc();
int hasPressColon();
int isCharCommandLegal(int i);
void clearCommandText();
int resolveCommandTextMode(int chValue, char *pString[], int *line_number, int max_len);
int resolveInsertMode(char *text[], int row, int col, int *line_number, int chValue, int max_len);
int resolveCommandMode(int chValue);
int beforeCommandTextMode(int ch);
int beforeInsertMode();
int beforeCommandMode();
int beforeSuspendMode();
void writeFile(char **text, int line);
void writeIntoFile(char *const *text, const int *line_number);
int isKeyToCommondText(char ch);
int findSubStringDownMove(char *const *text, const char *command, int start_row, int end_row, int start_col, int end_col);
void setMissKey(int arrogantKey, int ch);
int
findSubStringLoopInside(const char *command, char *const *text, int start_row, int begin_index, int end_index, int label);
void findStrDown(char *const *text, const int *line_number, const char *command);
void findStrUp(char *const *text, const int *line_number, const char *command);
void feedChar(char **text, int *line_number);
// 将二维数组指针，从第i行开始，往上方向移动1行
void moveLineUp(char **text, int *line_number, int beginRow, int max_len);
void pageDown(int *line_number);
void pageUp(int *line_number);
int cursor_row = 0;
int cursor_col = 0;

char *logPrint;
char *command;

int COMMAND_KEY_FLAG = 0x0000;// 判断是否按下了某个键
int COMMAND_STATE_FLAG = 0x0000;// 判断处于某种状态

char *fileName;
int isFileExist;

int should_show_log = 1;
int should_clear_log = 1;
int should_refresh_screen = 1;
int should_force_refresh_screen = 1;
int should_force_miss_key = 0;
int command_key_char = 0;

int arrogant_key = 0;
int miss_key = 0;

int has_catch_error_key = 0;

int begin_draw_row = 0;

extern int should_print;

void setShouldPrint(int);

int main(int argc, char *argv[]) {
    // should_print = 0;
    // setShouldPrint(1);
    // getShouldPrint();

    int sign;
    if (judgeArg(isArgLegal(argc, argv)) == FAIL)
        exit();
    fileName = argv[1];
    int fd = open(fileName, O_RDONLY); // 打开文件
    if (isFileLegal(fd, O_RDONLY) == FILE_OPEN_FAIL) {
        fd = open(fileName, O_CREATE);
        if (judgeFile(isFileLegal(fd, O_CREATE)) == FAIL)
            exit();
    }
    initGlobal();
    int *line_number = (int *) (malloc(sizeof(int)));
    char **file_text = readFile(fd, BUF_SIZE, MAX_LINE_NUMBER, MAX_LINE_INIT_LIMIT, MAX_LINE_SHOW_LIMIT, line_number);
    beforeCommandMode();
    int afterMode = MODE_COMMAND;
    while (1) {
        afterMode = show_text(file_text, line_number, MAX_LINE_SHOW_LIMIT, afterMode);
    }
}

void initGlobal() {
    cursor_row = 0;
    cursor_col = 0;
    logPrint = malloc1DimensionalChar(MAX_LINE_INIT_LIMIT);
    command = malloc1DimensionalChar(MAX_LINE_INIT_LIMIT);
    clearScreen();
}

/*
    ARG_DEFICIENCY(0x1000-1):  参数个数不足
    ARG_LEGAL(0x1000-0):  其他
*/
int isArgLegal(int argc, char *argv[]) {
    if (argc == 1) {
        return ARG_DEFICIENCY;
    }
    return ARG_LEGAL;
}

int judgeArg(int type) {
    if (type == ARG_DEFICIENCY) {
        prints("please input the command as [vi file_name]\n");
        return FAIL;
    }
    return SUCESS;
}

int isFileLegal(int fd, int type) {
    if (fd == -1) {
        if (type == O_RDONLY) {
            return FILE_OPEN_FAIL;
        } else if (type == O_CREATE) {
            return FILE_CREATE_FAIL;
        }
        isFileExist = 0;
    }
    isFileExist = 1;
    return FILE_LEGAL;
}

int judgeFile(int type) {
    if (type == FILE_OPEN_FAIL) {
        prints("please input the command as [vi file_name]\n");
        return FAIL;
    } else if (type == FILE_CREATE_FAIL) {
        prints("Create file failed!");
        return FAIL;
    }
    return SUCESS;
}

char *malloc1DimensionalChar(int size) {
    char *readyFor = malloc(size);
    memset(readyFor, '\0', size);
    return readyFor;
}

char **malloc2DimensionalChar(int size1, int size2) {
    char **aChar = malloc(size1);
    int i;
    for (i = 0; i < size1; i++)
        aChar[i] = malloc1DimensionalChar(size2);
    return aChar;
}

//拼接src的前n个字符到des
char *strcat_n(char *des, char *src, int len, int max_len) {
    if (len <= 0)
        return des;
    int pos = strlen(des);
    if (len + pos > max_len)
        len = max_len - pos;
//        return des;
    int i = 0;
    for (; i < len; i++)
        des[i + pos] = src[i];
    des[len + pos] = '\0';
    return des;
}

//拼接src到des
char *strcat2(char *des, char *src, int max_len) {
    int len = strlen(src);
    int pos = strlen(des);
    if (len + pos > max_len)
        return des;
    int i = 0;
    for (; i < len; i++)
        des[i + pos] = src[i];
    des[len + pos] = '\0';// 因为清空掉了，所以找不到了，谨记
    return des;
}

char *strcpy2(char *src, const char *target, int max_len) {
    int i;
    int len = strlen(target);
    for (i = 0; i < len; i++) {
        src[i] = target[i];
    }
    for (i = len; i <= max_len; i++) {
        src[i] = '\0';
    }
    return src;
}

// 从src开始，截取start，长度为end部分的字符串到target。成功返回子串，失败返回NULL
char *substr2(const char *src, char *target, int start, int length, int max_len) {
//    int len = strlen(src) - start;
    if (length > max_len || start < 0) {
        return NULL;
    }
    if (*(src + start) == '\0') {
        return target;
    }
    const char *after = src + start;
    int i, addLen;
    for (i = 0, addLen = 0; i < length && *after; i++, addLen++) {
        *target++ = *after++;
    }
    *target = '\0';
    return target - addLen;
}


// 从src开始，截取start，长度为end部分的字符串到target。成功返回子串，失败返回NULL
char *substr(const char *src, char *target, int start, int length) {
    int len = strlen(src) - start;
    if (length > len || start < 0) {
        return NULL;
    }
    const char *after = src + start;
    int i;
    for (i = 0; i < length; i++) {
        *target++ = *after++;
    }
    *target = '\0';
    return target - length;
}

char *strcatStable(char *des, char *src) {
    return strcat2(des, src, MAX_LINE_INIT_LIMIT);
}

int strcmp2(char *des, char *src) {
    int len1 = strlen(des);
    int i;
    for (i = 0; i < len1; i++) {
        if (src[i] == '\0' || des[i] == '\0')
            return 0;
        if (src[i] != des[i])
            return 0;
    }
    return 1;
}

// 查询q是不是p的子串，如果是的话，返回对应的下标，不是的话，返回-1
int strstr2(const char *p, const char *q) {
    int len = strlen(q);
    int cal;
    const char *last = p;
    while (*p && *q) {
        cal = 0;
        while (*p && *q && *p == *q) {
            p++, q++, cal++;
        }
        if (cal == len) {
            return (int) (p - last) - len;
        } else {
            q = q - cal;
        }
        if (!*p || !*q) {
            return -1;
        }
        p++;
    }
    return -1;
}

void printLog() {
    prints(logPrint);
    if (should_clear_log)
        if (logPrint != NULL) {
            free(logPrint);
            logPrint = malloc1DimensionalChar(MAX_LINE_INIT_LIMIT);
        }
}

void setLog(char *text) {
    logPrint = text;
}

void clearLog() {
    if (should_clear_log)
        logPrint = malloc1DimensionalChar(MAX_LINE_INIT_LIMIT);
}

// 强制清除日志
void clearLogForce() {
    if (logPrint != NULL) {
        free(logPrint);
        logPrint = malloc1DimensionalChar(MAX_LINE_INIT_LIMIT);
    }
}

void addLogPrint(char *description, int value) {
    addLogPrintStr(description);
    addLogPrintStr(":");
    addLogPrintStr(itoa2(value));
    addLogPrintStr("&");
}

void addLogPrintStr(char *str) {
    strcat2(logPrint, str, MAX_LINE_INIT_LIMIT);
}

void addCommand(char *str) {
    strcatStable(command, str);
}


// 获得去掉空格的命令
char *getCommand() {
    return trim(command);
}

char *itoa2(int a) {
    char *str = malloc(MAX_LINE_SHOW_LIMIT);
    char *beg = str;
    int sign;
    if ((sign = a) < 0) a = -a;
    do {
        *str++ = (char) ('0' + a % 10);
    } while ((a /= 10) > 0);
    if (sign < 0) *str++ = '-';
    *str = '\0';
    char *end = str - 1;
    str = beg;
    while (beg < end) {
        char tmp = *beg;
        *beg++ = *end;
        *end-- = tmp;
    }
    return str;
}

char *tempTrim;

char *trim(char *text) {
    int len = strlen(text);
    if (len == 0)
        return "";
    tempTrim = malloc(len);
    char *head = text;
    char *tempHead = tempTrim;
    while (*head != '\0') {
        if (*head != ' ' && *head != '\n' && *head != '\r')
            *tempTrim++ = *head;
        head++;
    }
    *tempTrim = *head;
    return tempHead;
}

int show_text(char *text[], int *line_number, int max_len, int mode) {
    int row = 0;
    if (has_catch_error_key == 0 && (should_refresh_screen == 1 || should_force_refresh_screen)) {
        should_force_refresh_screen = 0;
        row = draw(text, line_number, max_len) / MAX_ROW_LIMIT;
    }
    //char ch = getpid() + '0';
    // printf(1, "c = %c\n", ch);
    return wait_for_input(text, row, cursor_col, line_number, mode, max_len);
}

int beforeJ = 0;
int isFirst = 1;

int draw(char *text[], int *line_number, int max_len) {
//    printf("\n");
//    clearScreen();
    int j;
    for (j = *line_number; j < MAX_ROW_LIMIT - 1; j++)
        text[j] = malloc1DimensionalChar(max_len);
    if (isFirst || beforeJ != begin_draw_row) {
        int end = begin_draw_row + 12;
        for (j = begin_draw_row; j < end - 1; j++) {
            if (begin_draw_row < *line_number)
                if (j < *line_number)
                    printf(1, "%d%d%d|%s\n", (j + 1) / 100, ((j + 1) % 100) / 10, (j + 1) % 10,
                           text[j]);
                else
                    printf(1, "   |\n");
            else
                printf(1, "   |\n");
            drawCursor(line_number, j, cursor_col, text);
        }
        if (!DEBUG && should_show_log) {
            printLog();
        }
        isFirst = 0;
    }
    beforeJ = begin_draw_row;
    return j;
}


int wait_for_input(char *text[], int row, int col, int *line_number, int mode, int max_len) {
    has_catch_error_key = 0;
    int chValue = arrogant_key;
    char cValue;
    char input[MAX_LINE_INIT_LIMIT] = {};
//	if(mode == MODE_COMMAND)
    // setShouldPrint('a');
//	else
//			should_print = 1;
    // printf(1, "haha");
    if (!should_force_miss_key) {
        memset(input, 0, MAX_LINE_INIT_LIMIT);
        gets(input, 2);
//        gets2(input, 2, 0);
        chValue = (int) input[0];
        cValue = (char) chValue;
        // printf(1, "haha");
    }else{
        // printf(1, "haha");
        gets(input, 2);
//        gets2(input, 2, 0);
    }
    printf(1, "%c: %d, ", cValue, input[0]);
    should_force_miss_key = 0;
    if (mode == MODE_SUSPEND) {
        return resolveSuspendMode(chValue);
    } else if (mode == MODE_COMMAND) {
        return resolveCommandMode(chValue);
    } else if (mode == MODE_COMMAND_TEXT) {
        return resolveCommandTextMode(chValue, text, line_number, max_len);
    } else if (mode == MODE_INSERT) {
        return resolveInsertMode(text, row, col, line_number, chValue, max_len);
    }
    return MODE_COMMAND;
}

int resolveSuspendMode(int ch) {
    // 该模式下，可以显示日志，不可清空日志，不可清空屏幕
    // 进入除了CommandText的其他模式前，需要清空: / ? 标志
    if (isKeyToCommondText(ch)) {
        beforeCommandTextMode(ch);
        return MODE_COMMAND_TEXT;
    } else if (ch == KEY_INSERT || ch == KEY_LOWER_i) {
        beforeInsertMode();
        return MODE_INSERT;
    } else if (ch == KEY_LOWER_n || ch == KEY_UPPER_N) {
        if (command_key_char != 0) {
            if (command_key_char == KEY_DIV || command_key_char == KEY_QUESTION_MARK) {
                setMissKey(KEY_ENTER, ch);
                return MODE_COMMAND_TEXT;
            }
        }
    }
    return MODE_SUSPEND;
}

int beforeSuspendMode() {
    clearCommandText();
    clearCommandKeyFlag();
    should_clear_log = 0;
    should_show_log = 1;
    should_refresh_screen = 0;
    should_force_refresh_screen = 1;
}

void setMissKey(int arrogantKey, int ch) {
    arrogant_key = arrogantKey;
    miss_key = ch;
    should_force_miss_key = 1;
}

void clearMissKey() {
    arrogant_key = 0;
    miss_key = 0;
    should_force_miss_key = 0;
}

// 进入CommandText模式，此模式下。可以显示日志，不能清空日志，可以刷新屏幕
int resolveCommandTextMode(int chValue, char *text[], int *line_number, int max_len) {

    if (chValue == KEY_ENTER || chValue == KEY_LINE_FEED) {
        char *command = getCommand();
        // 进入SUSPEND，在获取键入的命令后，需要将之前的命令，日志无需清空
        if (strlen(command) <= 0) {

        } else if (command_key_char == KEY_COLON) {// 处理冒号后的事件
            if (strcmp2(command, COMMAND_QUIT)) {// 如果输入为q，表示退出
                if (hasStateWrite()) {// 如果已经写入，则直接退出
                    exit();
                } else {// 否则提示错误信息，进入SUSPEND模式
                    setLog("E37: No write since last change (add ! to override)");
                }
            } else if (strcmp2(command, COMMAND_QUIT_FORCE)) {// 如果输入为q!，表示强制退出
                exit();
            } else if (strcmp2(command, COMMAND_WRITE)) {// 如果输入为w，表示写入，设置标志位为已写入，并写入到文件中
                COMMAND_STATE_FLAG |= FLAG_STATE_HAS_WRITE;
                writeIntoFile(text, line_number);
            } else if (strcmp2(command, COMMAND_WRITE_QUIT)) {
                writeIntoFile(text, line_number);
                exit();
            } else {// 如果输入的为其他自身，则显示到log，加入到命令
                // 不能传入固定的字符数组，否则会引起内存泄露，但是我很多地方都没释放内存，反正全局释放了，大部分栈上会自动释放，可以不管，嘻嘻(*^__^*)
                char *temp = malloc1DimensionalChar(MAX_LINE_INIT_LIMIT);
                temp = strcpy2(temp, "E492: Not an editor command: ", MAX_LINE_INIT_LIMIT);
                setLog(strcatStable(temp, command));
            }
            beforeSuspendMode();
        } else if (command_key_char == KEY_DIV) {// 处理/后的事件
            // 命令即为需要检索的字符串
            if (miss_key != 0) {
                if (miss_key == KEY_LOWER_n)
                    findStrDown(text, line_number, command);
                else if (miss_key == KEY_UPPER_N)
                    findStrUp(text, line_number, command);
            } else
                findStrDown(text, line_number, command);

        } else if (command_key_char == KEY_QUESTION_MARK) {// 处理?后的事件
            if (miss_key != 0) {
                if (miss_key == KEY_LOWER_n)
                    findStrUp(text, line_number, command);
                else if (miss_key == KEY_UPPER_N)
                    findStrDown(text, line_number, command);
            } else
                findStrUp(text, line_number, command);
        }
        return MODE_SUSPEND;
    } else if (chValue == KEY_ESC) {
        // 进入COMMAND模式，需要将日志、按键标志、命令清空
        beforeCommandMode();
        return MODE_COMMAND;
    } else if (chValue == '-93') { ;
    } else {
        if (isCharCommandLegal(chValue)) {
            if (arrogant_key != 0 && miss_key != 0) {

            }
            should_show_log = 1;
            should_clear_log = 0;
            char com[2] = {chValue, '\0'};
            addLogPrintStr(com);
            addCommand(com);
        }
    }

    return MODE_COMMAND_TEXT;
}

char *cc;

void findStrUp(char *const *text, const int *line_number, const char *command) {
    int flag = findSubStringDownMove(text, command, cursor_row, 0, -1, cursor_col);
    char *temp = malloc1DimensionalChar(MAX_LINE_INIT_LIMIT);
    if (flag == 0) {
        flag = findSubStringDownMove(text, command, *line_number - 1, 0, -1, -1);
        if (flag == 0) {
            temp = strcpy2(temp, "E486: Pattern not found: ", MAX_LINE_INIT_LIMIT);
            setLog(strcatStable(temp, command));
        } else {
            temp = strcpy2(temp, "search hit TOP, continuing at BOTTOM", MAX_LINE_INIT_LIMIT);
            setLog(temp);
        }
    } else {
        cc = malloc(2);
        cc[0] = (char) command_key_char;
        cc[1] = '\0';
        setLog(strcatStable(cc, command));
    }
}


void findStrDown(char *const *text, const int *line_number, const char *command) {
    int flag = findSubStringDownMove(text, command, cursor_row, *line_number, cursor_col + 1, -1);
    char *temp = malloc1DimensionalChar(MAX_LINE_INIT_LIMIT);
    if (flag == 0) {
        flag = findSubStringDownMove(text, command, 0, cursor_row + 1, 0, -1);
        if (flag == 0) {
            temp = strcpy2(temp, "E486: Pattern not found: ", MAX_LINE_INIT_LIMIT);
            setLog(strcatStable(temp, command));
        } else {
            temp = strcpy2(temp, "search hit BOTTOM, continuing at TOP", MAX_LINE_INIT_LIMIT);
            setLog(temp);
        }
    } else {
        cc = malloc(2);
        cc[0] = (char) command_key_char;
        cc[1] = '\0';
        setLog(strcatStable(cc, command));
    }
}

// 要保证start_col 或者end_col至少有一个为-1
int findSubStringDownMove(char *const *text, const char *command, int start_row, int end_row, int start_col, int end_col) {
    int i;
    int flag = 0;
    int start_index = start_col, end_index = end_col;
    if (start_col != -1) {
        for (i = start_row; i < end_row; i++) {
            flag = findSubStringLoopInside(command, text, start_row, start_index, end_index, i);
            start_index = 0;
            if (flag == 1)
                break;
        }
    } else {
        for (i = start_row; i >= end_row; i--) {
            flag = findSubStringLoopInside(command, text, start_row, start_index, end_index, i);
            end_index = -1;
            if (flag == 1)
                break;
        }
    }
    return flag;
}

int
findSubStringLoopInside(const char *command, char *const *text, int start_row, int begin_index, int end_index, int label) {
    int len = strlen(text[start_row]);
    int command_len = strlen(command);
    if (begin_index <= len - 1) {
        const char *begin_char = text[label] + (begin_index == -1 ? 0 : begin_index);
        int remain_len = strlen(begin_char);
        if (remain_len >= command_len) {
            int pos = strstr2(begin_char, command);
            if (pos != -1) {// 找到下标所在位置，则移动过去
                if (end_index != -1 && pos >= end_index) {
                    return 0;
                }
                cursor_row = label;
                if (begin_index > 0)
                    cursor_col += pos + begin_index;
                else
                    cursor_col = pos;
                return 1;
            }
        }
    }
    return 0;
}

void writeIntoFile(char *const *text, const int *line_number) {
    writeFile(text, *line_number);
    char *temp = malloc1DimensionalChar(MAX_LINE_INIT_LIMIT);
    char *temp2 = malloc1DimensionalChar(MAX_LINE_INIT_LIMIT);
    char *temp3 = malloc1DimensionalChar(MAX_LINE_INIT_LIMIT);
    char *temp4 = malloc1DimensionalChar(MAX_LINE_INIT_LIMIT);
    char *temp5 = malloc1DimensionalChar(MAX_LINE_INIT_LIMIT);
    temp = strcpy2(temp, " written", MAX_LINE_INIT_LIMIT);
    temp2 = strcpy2(temp2, " [NEW]", MAX_LINE_INIT_LIMIT);
    temp3 = strcpy2(temp3, " ", MAX_LINE_INIT_LIMIT);
    temp4 = strcpy2(temp4, "\"", MAX_LINE_INIT_LIMIT);
    temp5 = strcpy2(temp5, "\" ", MAX_LINE_INIT_LIMIT);
    setLog(
            strcatStable(
                    strcatStable(
                            strcatStable(
                                    strcatStable(
                                            temp4, fileName),
                                    temp5),
                            isFileExist ? temp2 : temp3),
                    temp)
    );
}

int isKeyToCommondText(char ch) {
    if (ch == KEY_COLON || ch == KEY_QUESTION_MARK || ch == KEY_DIV)
        return 1;
    return 0;
}

// 进入CommandText前，需要清空日志
int beforeCommandTextMode(int ch) {
    clearLogForce();
    clearCommandText();
    clearCommandKeyFlag();
    char command_key[2] = {(char) ch, '\0'};
    addLogPrintStr(command_key);

    command_key_char = ch;

    should_clear_log = 0;
    should_show_log = 1;
    should_refresh_screen = 1;

}

int resolveInsertMode(char *text[], int row, int col, int *line_number, int chValue, int max_len) {
    // 进入到insert模式下，禁止清空日志，可以显示日志，可以刷新屏幕
    if (chValue == KEY_LEFT) {
        moveCursor(SET_COL, SUB, line_number, text, SET_COL, 0);
    } else if (chValue == KEY_RIGHT) {
        moveCursor(SET_COL, ADD, line_number, text, SET_COL, 0);

    } else if (chValue == KEY_DOWN) {
        moveCursor(SET_ROW, ADD, line_number, text, SET_ROW, 0);
        if (cursor_row >= begin_draw_row + 11 && cursor_row <= *line_number - 1) {
            begin_draw_row++;
        }
    } else if (chValue == KEY_UP) {
        moveCursor(SET_ROW, SUB, line_number, text, SET_ROW, 0);
        if (cursor_row < begin_draw_row && cursor_row >= 0) {
            begin_draw_row--;
        }
    } else if (chValue == KEY_ESC) { // ESC 输入ESC，进入COMMAND模式，禁制刷新屏幕
        beforeCommandMode();
        draw(text, line_number, max_len);
        return MODE_COMMAND;
    } else if (chValue == KEY_END || chValue == KEY_CTRL_E) { // END
        int maxLengthLabel = getCurrentMaxLengthLabel(text);
        cursor_col = maxLengthLabel == 0 ? 0 : maxLengthLabel + 1;
    } else if (chValue == KEY_HOME || chValue == KEY_CTRL_A) {
        cursor_col = 0;
    } else if (chValue == KEY_BACK_SPACE) {
        deleteChar(text, line_number, cursor_row, cursor_col);
    } else if (chValue == KEY_PAGE_DOWN) {
        pageDown(line_number);
    } else if (chValue == KEY_PAGE_UP) {
        pageUp(line_number);
    } else if (chValue == 224) {
        has_catch_error_key = 1;
    } else if (chValue == KEY_LINE_FEED || chValue == KEY_ENTER) {
        feedChar(text, line_number);
    } else {
        insertChar(text, chValue, line_number, cursor_row, cursor_col);
    }
    return MODE_INSERT;
}

void pageDown(int *line_number) {
    int lastLineLabel = begin_draw_row + 11;
    if (lastLineLabel >= *line_number - 1)
        cursor_row = *line_number - 1;
    else
        cursor_row = lastLineLabel - 1;
    begin_draw_row = cursor_row;
}

void pageUp(int *line_number) {
    int last_init_page_row = begin_draw_row - MAX_ROW_LIMIT;
    if (last_init_page_row < 0)
        cursor_row = 0;
    else
        cursor_row = last_init_page_row;
    begin_draw_row = cursor_row;
}

int beforeInsertMode() {// 设置log为 --insert--
    clearLogForce();
    clearCommandKeyFlag();
    clearCommandText();
    char *temp = malloc1DimensionalChar(MAX_LINE_INIT_LIMIT);
    temp = strcpy2(temp, "-- INSERT --", MAX_LINE_INIT_LIMIT);
    setLog(strcatStable(temp, command));
    should_refresh_screen = 1;
    should_clear_log = 0;
    should_show_log = 1;

    command_key_char = 0;
}

int resolveCommandMode(int chValue) {
    // Command模式下，禁止刷新屏幕，禁止显示日志，可以清空日志
    if (isKeyToCommondText(chValue)) {
        beforeCommandTextMode(chValue);
        return MODE_COMMAND_TEXT;
    } else if (chValue == KEY_INSERT || chValue == KEY_LOWER_i) {
        beforeInsertMode();
        return MODE_INSERT;
    }
    return MODE_COMMAND;
}

int beforeCommandMode() {
    should_show_log = 0;
    should_clear_log = 1;
    should_refresh_screen = 0;
    should_force_refresh_screen = 1;
    clearLogForce();
    clearCommandKeyFlag();
    clearCommandText();


}

// 清楚命令标志
void clearCommandKeyFlag() {
    COMMAND_KEY_FLAG &= FLAG_CLEAR;
}

void clearCommandStatusFlag() {
    COMMAND_STATE_FLAG &= FLAG_CLEAR;
}

void clearCommandBool() {
    should_show_log = 0;
    should_clear_log = 0;
}

// 清楚命令文本
void clearCommandText() {
    if (command != NULL) {
        free(command);
        command = malloc1DimensionalChar(MAX_LINE_INIT_LIMIT);
    }
}

int isCharCommandLegal(int c) {
    if ('0' <= c && c <= 9 || 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '!' || c == 8 || c == ' ')
        return 1;
    return 0;
}

int hasStateWrite() {
    return COMMAND_STATE_FLAG & FLAG_STATE_HAS_WRITE;
}

int hasPressEsc() {
    return COMMAND_KEY_FLAG & FLAG_KEY_HAS_PRESS_ESC;
}

int hasPressColon() {
    return COMMAND_KEY_FLAG & FLAG_KEY_HAS_PRESS_COLON;
}

void insertChar(char **text, int ch, int *line_number, int row, int col) {
    insertCharInside(text, ch, line_number, row, col);
    moveCursor(SET_COL, ADD, line_number, text, SET_COL, EVENT_INSERT);
}

void deleteChar(char **text, int *line_number, int row, int col) {
    int moveOrStay = deleteCharInside(text, row, col, line_number);
    if (moveOrStay == EVENT_DELETE_MOVE)
        moveCursor(SET_COL, SUB, line_number, text, SET_COL, EVENT_DELETE);
}

void feedChar(char **text, int *line_number) {
    // 新增行，并且将光标所在列到当前行的结束之间的字符串作为下一行初始字符串，同时光标下移至下一行开头
    char *current_row = text[cursor_row];
    char *temp = malloc1DimensionalChar(MAX_LINE_INIT_LIMIT);
    temp = substr2(current_row, temp, cursor_col, getCurrentMaxLength(text), MAX_LINE_SHOW_LIMIT);
    createNewTextLine(text, line_number);
    // 将下一行往后移动一行
    int i;
    for (i = *line_number - 1; i > cursor_row; i--) {
        strcpy2(text[i], text[i - 1], MAX_LINE_SHOW_LIMIT);
    }
    strcpy2(text[cursor_row + 1], temp, MAX_LINE_SHOW_LIMIT);// 赋值给下一行
    for (i = cursor_col; i < strlen(text[cursor_row]); i++) {
        text[cursor_row][i] = '\0';
    }
    cursor_col = 0;
    cursor_row += 1;


}

int deleteCharInside(char **text, int row, int col, int *line_number) {
    int i;
    int length = getMaxLength(text, row);
    if (col == 0) {// 如果指向第一个位置，将当前行拼接到上一行，光标指向上一行的行尾
        if (cursor_row == 0) {// 当前是第一行则不移动
            return EVENT_DELETE_STAY;
        } else if (getMaxLength(text, cursor_row) == 0) {
            // 如果当前行是空的，则将下面的行往上移，同时指向上一行的行尾+1
            moveLineUp(text, line_number, cursor_row + 1, MAX_LINE_SHOW_LIMIT);
        } else {
            // 计算上一行还能容纳多少字符
            int last_row = cursor_row - 1;
            int remain = MAX_LINE_SHOW_LIMIT - getMaxLength(text, last_row);
            char *target = malloc1DimensionalChar(MAX_LINE_SHOW_LIMIT);
            // 获取光标指向当前行remain的字符
            target = substr2(text[cursor_row], target, 0, remain, MAX_LINE_SHOW_LIMIT);
            strcat2(text[last_row], target, MAX_LINE_SHOW_LIMIT);
            // 将当前行remain后的字符向前移动
            int i, j;
            int maxLength = getCurrentMaxLength(text);
            for (i = remain, j = 0; i < maxLength; i++, j++) {
                text[cursor_row][j] = text[cursor_row][i];
            }
            for (; j < maxLength; j++) {
                text[cursor_row][j] = '\0';
            }
        }
        cursor_row = cursor_row - 1;
        cursor_col = getCurrentMaxLength(text);
        return EVENT_DELETE_STAY;
    } else if (col == length) {// 如果指向的是最后一个位置，则将前一个位置的值变为\0
        text[row][length - 1] = '\0';
        // 如果前一个位置的下标为-1，则表示是上面的情况
    } else {// 否则，向前移动，并且将倒数第一个位置置为\0
        for (i = col; i <= length; i++) {
            text[row][i - 1] = text[row][i];
        }
    }
    return EVENT_DELETE_MOVE;
}

// 将二维数组指针，从第i行开始，往上方向移动1行
void moveLineUp(char **text, int *line_number, int beginRow, int max_len) {
    if (beginRow == 0) {
        return;
    }
    int i, j;
    for (i = beginRow; i < *line_number; i++) {
        for (j = 0; j < max_len; j++) {
            text[i - 1][j] = text[i][j];
        }
    }
    for (i = 0; i < max_len; i++) {
        text[*line_number - 1][i] = '\n';
    }
    *line_number = *line_number - 1;
}

void insertCharInside(char **text, int ch, int *line_number, int row, int col) {
    int j;
    if (row > *line_number - 1) {// 如果当前行还未新增的话，则新增一行
        createNewTextLine(text, line_number);
    }
    int maxLengthLabel = getMaxLengthLabel(text, row);
    if (col > maxLengthLabel) {
        // 如果要插入的位置大于所在位置, 则将当前字符插入到下一行的第一个
        if (col >= MAX_LINE_SHOW_LIMIT - 1) {
            insertCharInside(text, ch, line_number, row + 1, 0);
            return;
        }
        // 否则，小于最大显示字符，则直接插入，并让它们之间的字符为空格
        int k;
        for (k = maxLengthLabel + 1; k < col; k++)
            text[row][k] = ' ';
    } else {
        for (j = maxLengthLabel; j >= col; j--) {
            if (j == col - 1)
                break;
            else if (row == *line_number - 1) { // 如果当前行是最后一行
                if (j == maxLengthLabel) { // 如果是最后一个
                    if (j >= MAX_LINE_SHOW_LIMIT - 1) {// 判断是否超过字符上限
                        // 达到字符上限，新增行，将最后一个字符传给新增行的第一个字符
                        createNewTextLine(text, line_number);
                        text[*line_number - 1][0] = text[row][maxLengthLabel];
                    } else {
                        text[row][j + 1] = text[row][j];
                    }
                } else {// 如果没有，直接传给下一个字符
                    text[row][j + 1] = text[row][j];
                }
            } else { // 如果当前行不是最后一行
                if (j == maxLengthLabel) {// 如果是最后一个
                    if (j >= MAX_LINE_SHOW_LIMIT - 1) {// 判断是否超过字符上限，减1是为了防止当前行达到字符上限，但却多加了一个字符的情况
                        // 达到字符上限，则进行下一行的移动，要插入的位置为下一行的第一个，字符为当前行的最后一个字符
                        insertCharInside(text, text[row][maxLengthLabel], line_number, row + 1, 0);
                    } else {// 如果没有，直接传给下一个字符
                        text[row][j + 1] = text[row][j];
                    }
                } else {// 如果不是最后一个，则直接传给下一个车字符
                    text[row][j + 1] = text[row][j];
                }
            }
        }
    }
    // 将当前行的当前字符用传入字符替换
    text[row][col] = (char) ch;
}

void createNewTextLine(char **text, int *line_number) {
    text[*line_number] = malloc1DimensionalChar(MAX_LINE_SHOW_LIMIT);
    *line_number = *line_number + 1;
}

void drawCursor(int *line_number, int row, int col, char **text) {
    printf(1, "%s\n", blank_same_cpy(4, row, col, MAX_LINE_INIT_LIMIT));
}

char *blank_same_cpy(int before, int row, int col, int max_length) {
    int i;
    char *before_ch = malloc1DimensionalChar(max_length + before);
    char *header = before_ch;
    for (i = 0; i < before - 1; i++) {
        *before_ch = '-';
        before_ch++;
    }
    *before_ch = '|';
    before_ch++;
    for (i = 0; i < col; i++) {
        *before_ch = ' ';
        before_ch++;
    }
    if (row == cursor_row) {
        *before_ch = VIEW_CURSOR;
        before_ch++;
    }
    before_ch = header;
    return before_ch;
}


// 将传入的列下标或者行下标减一或者加一
int moveCursor(int rowOrCol, int type, int *line_number, char **text, int lastRowOrCol, int event) {
    if (rowOrCol == SET_ROW) {
        if (type == ADD) {
            cursor_row++;
        } else if (type == SUB) {
            cursor_row--;
        }
    } else if (rowOrCol == SET_COL) {
        if (type == ADD) {
            cursor_col++;
        } else if (type == SUB) {
            cursor_col--;
        }
    }
    return cursorNext(rowOrCol, line_number, text, lastRowOrCol, type, event);
}

// 对已经加减后的行列值进行判断
int cursorNext(int rowOrCol, int *line_number, char **text, int lastRowOrCol, int type, int event) {

    int judgeResult = EQUAL_EVER;
    if (rowOrCol == SET_ROW) {
        if (cursor_row < 0) {
            cursor_row = 0;
            return ROW_LESS;
        } else if (cursor_row >= *line_number) {
            cursor_row = *line_number - 1;
            return ROW_MORE;
        } else {
            int new_row_max_col = getCurrentMaxLengthLabel(text); // 已经加减后的当行的最大下标
            int new_row_max_len = getCurrentMaxLength(text);
            cursor_col = cursor_col <= new_row_max_col ? cursor_col : new_row_max_col;
        }
        if (lastRowOrCol == SET_COL) {// 如果设置列值，同时造成小于0或大于极限
            int new_row_max_col = getCurrentMaxLengthLabel(text); // 已经加减后的当行的最大下标
            int new_row_max_len = getCurrentMaxLength(text);
            if (type == ADD) {// 如果向右移动
                if (event == EVENT_INSERT) // 如果是插入导致移动的话，指向下标为1
                    cursor_col = 1;
                else
                    cursor_col = 0;
            }
            if (type == SUB)
                // 如果当前行是空行，则光标指向第0个位置，否则执行当前行最大字符+1的位置
                cursor_col = new_row_max_len == 0 ? new_row_max_col : new_row_max_col + 1;
        }
    } else if (rowOrCol == SET_COL) {
        int new_row_max_col = getCurrentMaxLengthLabel(text); // 已经加减后的当行的最大下标
        int new_row_max_len = getCurrentMaxLength(text);
        if (cursor_col < 0) {
            if (event == EVENT_DELETE) {// 如果执行删除，则不继续判断行是否超出范围。
                return judgeResult;
            }
            judgeResult = cursorColToRow(SUB, COL_LESS, line_number, text, lastRowOrCol, 0);
        } else if (cursor_col > new_row_max_col + 1 || new_row_max_len == 0) {
            // 如果是执行了插入后，才进入到这个判断的话，会导致new_row_max_col还没有改变，也就还是未插入前的值，所以需要加多一个判断
            if (event == EVENT_INSERT) {
                if (cursor_col < MAX_LINE_SHOW_LIMIT) {// 执行插入后，之前行未达到字符上限，则不用去判断了
                    return judgeResult;
                } else {// 否则，因为新增了一行或者插入到下一行的第一个字符，所以需要指向下标为1的位置
                    cursor_col = cursor_row >= *line_number - 1 ? getCurrentMaxLengthLabel(text) + 1 : 1;
                }
            } else if (event == EVENT_DELETE) {// 如果执行删除，则不继续判断行是否超出范围。
                return judgeResult;
            } else {
                // 如果光标大于最大长度+1，或者当前行是空行，则将光标跳转到下一行第一个
                cursor_col = cursor_row >= *line_number - 1 ? getCurrentMaxLengthLabel(text) + 1 : 0;
            }
            judgeResult = cursorColToRow(ADD, COL_MORE, line_number, text, lastRowOrCol, event);
        }
    }
    return judgeResult;
}

int getCurrentMaxLengthLabel(char **text) {
    int new_row_max_col = getCurrentMaxLength(text) - 1;
    return new_row_max_col < 0 ? 0 : new_row_max_col;
}

int getCurrentMaxLength(char **text) {
    return getMaxLength(text, cursor_row);
}

int getMaxLengthLabel(char **text, int row) {
    return getMaxLength(text, row) - 1;
}

int getMaxLength(char **text, int row) {
    return strlen(text[row < 0 ? 0 : row]);
}

int cursorColToRow(int type, int col_type, int *line_number, char **text, int lastRowOrCol, int event) {
    int current = moveCursor(SET_ROW, type, line_number, text, lastRowOrCol, event);
    if (current == ROW_LESS) {
        if (col_type == COL_LESS) {
            return COL_LESS_ROW_LESS;
        } else if (col_type == COL_MORE) {
            return COL_MORE_ROW_LESS;
        }
    } else if (current == ROW_MORE) {
        if (col_type == COL_LESS) {
            return COL_LESS_ROW_MORE;
        } else if (col_type == COL_MORE) {
            return COL_MORE_ROW_MORE;
        }
    }
    return col_type;
}


void show_text_same(char *text, int line_number) {
    int i = 0;
    for (i = 0; i < line_number; i++) {
        prints(text);
    }
}

void clearScreen() {
    show_text_same("\n", 24);
}

void prints(char *text) {
    printf(1, text);
}

void log(char *text) {
    if (!DEBUG) {
        printf(1, "%s\n", text);
        prints("------------------------\n");
    }
}

void logi(char *statement, int intValue) {
    if (!DEBUG) {
        printf(1, "%s%d\n", statement, intValue);
        prints("------------------------\n");
    }
}

int maxLen = 0;

char **readFile(int fd, int buf_size, int text_num, int text_length, int max_len, int *line_number) {
    char *buf = malloc(buf_size);
    char **text = malloc(text_num);
    text[0] = malloc1DimensionalChar(text_length);
    int len;
    *line_number = 0;
    while ((len = read(fd, buf, buf_size)) > 0) {
        maxLen += len;
        int i = 0;
        int next = 0;
        int is_full = 0;
        while (i < len) {
            for (i = next; i < len && buf[i] != '\n'; i++);
            strcat_n(text[*line_number], buf + next, i - next, max_len);
            if (i < len && buf[i] == '\n') {
                if (*line_number >= text_num - 1)
                    is_full = 1;
                else {
                    *line_number = *line_number + 1;
                    text[*line_number] = malloc1DimensionalChar(text_length);
                }
            }
            if (is_full == 1 || i >= len - 1)
                break;
            else
                next = i + 1;
        }
        if (is_full == 1)
            break;
    }
    return text;
}

int clearFile() {
    int i, j;
    int fd = open(fileName, O_WRONLY); // 打开文件
    char *blank = malloc1DimensionalChar(maxLen);
    if (isFileLegal(fd, O_WRONLY) == FILE_LEGAL) {
        write(fd, blank, maxLen);
        return SUCESS;
    }
    return FAIL;
}

void writeFile(char **text, int line) {
    int i;
    int fd = open(fileName, O_WRONLY); // 打开文件

    char **write_content = malloc2DimensionalChar(line * MAX_LINE_INIT_LIMIT, MAX_LINE_INIT_LIMIT);
    if (isFileLegal(fd, O_WRONLY) == FILE_LEGAL) {
        for (i = 0; i < line; i++) {
            int label = getMaxLengthLabel(text, i);
            write_content[i] = strcpy2(write_content[i], text[i], MAX_LINE_INIT_LIMIT);
            write_content[i][label + 1] = '\n';
            write_content[i][label + 2] = '\0';
        }
        for (i = 0; i < line; i++) {
            write(fd, write_content[i], strlen(write_content[i]));
        }
    }
}

char *setString(char *source) {
    int len = 0;
    while (*source != '\0') {

    }
}